package com.czk.classreader.counttime.practice;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;

import static org.objectweb.asm.Opcodes.*;

/**
 * @Author:ChenZhangKun
 * @Date: 2021/10/19 22:43
 */
public class CostTimeVisitor extends ClassVisitor {
    private boolean isInterface;
    private String owner;

    public CostTimeVisitor(int api, ClassVisitor classVisitor) {
        super(api, classVisitor);
    }

    /**
     * 创建类的时候访问
     *
     * @param version
     * @param access
     * @param name
     * @param signature
     * @param superName
     * @param interfaces
     */
    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        super.visit(version, access, name, signature, superName, interfaces);
        this.owner = name;
        System.out.println(this.owner);
        this.isInterface = (access & ACC_INTERFACE) != 0;
        System.out.println(isInterface);
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
        // 原来的method
        MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
        // 排除构造和静态代码块
        if (methodVisitor != null && !isInterface && !"<init>".equals(name) && !"<cinit>".equals(name)) {
            // 不是本地方法
            boolean isNative = (access & ACC_NATIVE) != 0;
            boolean isAbstract = (access & ACC_ABSTRACT) != 0;
            if (!isNative && !isAbstract) {
                // 返回新的
                methodVisitor = new CostTimeAdaptor(api, methodVisitor, owner);
            }
        }
        return methodVisitor;
    }

    /**
     * 添加成员变量
     */
    @Override
    public void visitEnd() {
        if (!isInterface) {
            FieldVisitor fieldVisitor = super.visitField(ACC_PUBLIC | ACC_STATIC, "timer", "J", null, null);
            if (fieldVisitor != null) {
                fieldVisitor.visitEnd();
            }
        }
        // 父类的visitEnd方法
        super.visitEnd();
    }

    /**
     * 成员内部类实现
     */
    private class CostTimeAdaptor extends MethodVisitor {
        private final String owner;
        public CostTimeAdaptor(int api, MethodVisitor methodVisitor, String owner) {
            super(api, methodVisitor);
            this.owner = owner;
        }

        /**
         * 方法进入时计算当前时间
         */
        @Override
        public void visitCode() {
            // 访问timer
            super.visitFieldInsn(GETSTATIC, owner, "timer", "J");
            // 执行方法
            super.visitMethodInsn(INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);
            // 赋值
            super.visitInsn(LSUB);
            // 赋值
            super.visitFieldInsn(PUTSTATIC, owner, "timer", "J");
            super.visitCode();
        }

        @Override
        public void visitInsn(int opcode) {
            if ((opcode >= IRETURN || opcode <= RETURN) || opcode == ATHROW) {
                super.visitFieldInsn(GETSTATIC, owner, "timer", "J");
                super.visitMethodInsn(INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);
                super.visitInsn(LADD);
                super.visitFieldInsn(PUTSTATIC, owner, "timer", "J");
            }
            super.visitInsn(opcode);
        }
    }
}
